<?php
/**
 * http://code.google.com/p/php-iterator-utils/
 * @license http://www.apache.org/licenses/LICENSE-2.0.html
 * @author Seva Lapsha (seva.lapsha@gmail.com)
 */
namespace lapsha\iterators\assoc {
	include_once __DIR__.'/../common.php';
	use \lapsha\common;
	include_once __DIR__.'/common.php';
	use \lapsha\iterators\common\Wrapper;

	/**
	 * Generate Iterator by flipping keys and vals of given Iterator
	 * @see array_flip
	 */
	class Flipper extends Wrapper {
		function current() {
			return parent::key();
		}
		function key() {
			return parent::current();
		}
	}

	/**
	 * Generate Iterator by applying calback to keys and vals of given Iterator
	 * @see array_walk, array_map
	 */
	class Mapper extends Wrapper {
		protected $callback;
		protected $key;
		protected $current;
		protected $mapped;
		/**
		 * @param \Iterator $i
		 * @param calback $callback to return array of single key-value pair
		 */
		function __construct(\Iterator $i, $callback) {
			common\checkCallable($callback);
			parent::__construct($i);
			$this->callback = $callback;
		}
		function current() {
			$entry = $this->map();
			return reset($entry);
		}
		function key() {
			$entry = $this->map();
			reset($entry);
			return key($entry);
		}
		protected function map() {
			$entry = call_user_func($this->callback, $this->i->key(), $this->i->current());
			if (!is_array($entry) || count($entry) != 1)
				trigger_error('Incompatible return value', \E_USER_WARNING);
			return $entry;
		}
	}
	/**
	 * Filter iterator using given callback
	 * @see array_filter
	 */
	class Filter extends \FilterIterator {
		protected $callback;
		/**
		 * @param \Iterator $i
		 * @param <type> $callback to receive val (and optionally key) and return boolean
		 */
		function __construct(\Iterator $i, $callback) {
			common\checkCallable($callback);
			parent::__construct($i);
			$this->callback = $callback;
		}

		public function accept() {
			return call_user_func($this->callback, $this->current(), $this->key());
		}
	}
	/**
	 * Generate Iterator by zipping given 2 Iterators' values as keys and values
	 * @see array_combine
	 */
	class Combiner extends \DualIterator {
		/**
		 * @param \Iterator $i keys
		 * @param \Iterator $j vals
		 */
		function __construct(\Iterator $i, \Iterator $j) {
			parent::__construct($i, $j, \DualIterator::KEY_LHS | \DualIterator::CURRENT_RHS);
		}
	}
	/**
	 * Generate Iterator by filling keys with given Iterator values and vals with a constant value
	 * @see array_fill_keys
	 */
	class KeyFiller extends Mapper {
		/**
		 * @param \Iterator $i
		 * @param $val
		 */
		function __construct(\Iterator $i, $val) {
			parent::__construct($i, function($key, $current) use($val) {return array($current => $val);});
		}
	}
}